<!--
* @author wn
* @date 2023/12/27 10:35:58
* @description: 订单详情页
!-->
<template>
	<!-- 自定义吸顶导航栏: 默认透明不可见, scroll-view 滚动到 50 时展示 -->
	<view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
		<navigator
			v-if="pages.length > 1"
			open-type="navigateBack"
			class="back icon-left"
		></navigator>
		<navigator
			v-else
			url="/pages/index/index"
			open-type="switchTab"
			class="back icon-home"
		>
		</navigator>
		<view class="title">订单详情</view>
	</view>
	<scroll-view scroll-y class="viewport" id="scroller" @scrolltolower="getMore">
		<template v-if="orderDetail">
			<!-- 订单状态 -->
			<view
				class="overview"
				:style="{ paddingTop: safeAreaInsets!.top + 20 + 'px' }"
			>
				<!-- 待付款状态:展示去支付按钮和倒计时 -->
				<template v-if="orderDetail?.orderState === OrderState.WaitForPay">
					<view class="status icon-clock">等待付款</view>
					<view class="tips">
						<text class="money">应付金额: ¥ {{ orderDetail.payMoney }}</text>
						<text class="time">支付剩余</text>
						<!-- 倒计时组件 -->
						<uni-countdown
							:second="orderDetail.countdown"
							color="#fff"
							splitor-color="#fff"
							:show-day="false"
							:show-colon="false"
							@timeup="onTimeUp"
						/>
					</view>
					<view class="button" @tap="onOrderPay">去支付</view>
				</template>
				<!-- 其他订单状态:展示再次购买按钮 -->
				<template v-else>
					<!-- 订单状态文字 -->
					<view class="status">
						{{
							orderDetail
								? orderStateList[orderDetail.orderState].text
								: '状态未知'
						}}
					</view>
					<navigator
						class="button button-group"
						:url="`/pagesOrder/create/create?orderId=${id}`"
						hover-class="none"
					>
						再次购买
					</navigator>
					<!-- 待发货状态：模拟发货,开发期间使用,用于修改订单状态为已发货
          项目上线后应该是由商家发货,拉取订单状态为 已发货 -->
					<view
						v-if="orderDetail?.orderState === OrderState.WaitForDelivery"
						class="button button-group"
						@tap="onOrderDelivery"
					>
						模拟发货
					</view>
					<!-- 待收货状态: 展示确认收货按钮 -->
					<view
						v-if="orderDetail?.orderState === OrderState.WaitForReceived"
						class="button button-group"
						@tap="onOrderConfirm"
					>
						确认收货
					</view>
				</template>
			</view>
			<!-- 配送状态 -->
			<view class="shipment">
				<!-- 订单物流信息 -->
				<template v-if="logisticList.length">
					<view v-for="add in logisticList" :key="add.id" class="item">
						<view class="text-one">{{ add.text }} </view>
						<view class="text-two"> {{ add.time }} </view>
					</view>
				</template>
				<!-- 没有发货 -->
				<view v-else class="item text-one"> 没有发货,暂无物流信息 </view>
				<!-- 用户收货地址 -->
				<view class="locate">
					<view class="text-one">
						{{ orderDetail?.receiverContact }}
						{{ orderDetail?.receiverMobile }}
					</view>
					<view class="text-two"> {{ orderDetail?.receiverAddress }} </view>
				</view>
			</view>
			<!-- 商品信息 -->
			<view class="goods">
				<navigator
					class="navigator"
					v-for="item in orderDetail?.skus"
					:key="item.id"
					:url="`/pages/goods/goods?id=${item.spuId}`"
					hover-class="none"
				>
					<image class="cover" :src="item.image"></image>
					<view class="meta">
						<view class="name ellipsis">{{ item.name }}</view>
						<text class="attrs">{{ item.attrsText }}</text>
						<view class="prices">
							<view class="price symbol">{{ item.curPrice }}</view>
							<view class="count">{{ item.quantity }}</view>
						</view>
					</view>
				</navigator>
				<!-- 待评价状态:展示按钮 -->
				<view
					class="action"
					v-if="orderDetail?.orderState === OrderState.WaitForEvaluate"
				>
					<navigator url="" class="button"> 去评价 </navigator>
					<view class="button primary">申请售后</view>
				</view>
				<!-- 合计 -->
				<view class="row row-top">
					<view class="text">商品总价: </view>
					<view class="symbol">{{ orderDetail?.totalMoney }}</view>
				</view>
				<view class="row">
					<view class="text">运费: </view>
					<view class="symbol">{{ orderDetail?.postFee }}</view>
				</view>
				<view class="row row-bottom">
					<view class="text">应付金额: </view>
					<view class="symbol primary">{{ orderDetail?.payMoney }}</view>
				</view>
			</view>
			<!-- 订单信息 -->
			<view class="detail">
				<view class="title">订单信息</view>
				<text class="item row"> 订单编号: {{ id }} </text>
				<text class="item row copy" @tap="onCopy(id)">复制</text>
				<view class="item">下单时间: {{ orderDetail?.createTime }}</view>
			</view>
			<!-- 猜你喜欢 -->
			<XtxGuess ref="guessRef" />
			<!-- 底部操作栏 -->
			<view
				class="toolbar"
				:style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }"
			>
				<!-- 待付款状态:展示支付按钮 -->
				<template v-if="orderDetail?.orderState === OrderState.WaitForPay">
					<view class="button" @tap="popup?.open?.()"> 取消订单 </view>
					<view class="button primary" @tap="onOrderPay"> 去支付 </view>
				</template>
				<!-- 其他订单状态:按需展示按钮 -->
				<template v-else>
					<navigator
						class="button secondary"
						:url="`/pagesOrder/create/create?orderId=${id}`"
						hover-class="none"
					>
						再次购买
					</navigator>
					<!-- 待收货状态: 展示确认收货 -->
					<view
						v-if="orderDetail?.orderState === OrderState.WaitForReceived"
						class="button primary"
						@tap="onOrderConfirm"
					>
						确认收货
					</view>
					<!-- 待评价状态: 展示去评价 -->
					<view
						v-if="orderDetail?.orderState === OrderState.WaitForEvaluate"
						class="button"
					>
						去评价
					</view>
					<!-- 待评价/已完成/已取消 状态: 展示删除订单 -->
					<view
						v-if="
							orderDetail
								? orderDetail.orderState >= OrderState.WaitForEvaluate
								: false
						"
						class="button delete"
						@tap="onDeleteOrder"
					>
						删除订单
					</view>
				</template>
			</view>
		</template>
		<template v-else>
			<!-- 骨架屏组件 -->
			<detail-skeleton />
		</template>
	</scroll-view>
	<!-- 取消订单弹窗 -->
	<uni-popup ref="popup" type="bottom" background-color="#fff">
		<view class="popup-root">
			<view class="title">订单取消</view>
			<view class="tips">请选择取消订单的原因：</view>
			<view
				class="cell"
				v-for="item in reasonList"
				:key="item"
				@tap="reason = item"
			>
				<text class="text">{{ item }}</text>
				<text
					class="icon"
					:class="{
						'icon-ring': item !== reason,
						'icon-checked': item === reason,
					}"
				></text>
			</view>
			<view class="footer">
				<button class="button" @tap="popup?.close?.()">取消</button>
				<button class="button primary" @tap="onOrderCancel">确认</button>
			</view>
		</view>
	</uni-popup>
</template>
<script lang="ts" setup>
import {
	getOrderDetailApi,
	getOrderConsignmentApi,
	putOrderConfirmApi,
	deleteOrderApi,
	putOrderCancelApi,
	getOrderLogisticsApi,
} from '@/api/order'
import { useGuess } from '@/hook/useGuess'
import { onLoad, onReady } from '@dcloudio/uni-app'
import { ref } from 'vue'
import { OrderState, orderStateList } from '@/types/orderState'
import { getPayMockApi, getWxPayApi } from '@/api/pay'
import DetailSkeleton from './components/DetailSkeleton.vue'

// 订单 id
const { id } = defineProps<{ id: string }>()

// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()

// 猜你喜欢
const { guessRef, getMore } = useGuess()

// 弹出层组件
const popup = ref<UniHelper.UniPopupInstance>()

// 取消原因列表
const reasonList = ref([
	'商品无货',
	'不想要了',
	'商品信息填错了',
	'地址信息填写错误',
	'商品降价',
	'其它',
])

// 订单取消原因
const reason = ref('')

// 复制内容
const onCopy = (id: string) => {
	// 设置系统剪贴板的内容
	uni.setClipboardData({ data: id })
}

/**
 * 滚动驱动的动画
 * 1 小程序原生 -- this.animate(selector, keyframes, duration, ScrollTimeline)
 * 2 css animation-timeline
 */

// 获取页面栈
const pages = getCurrentPages()

// 基于原生小程序的 Page 类型扩展 uni-app 的 Page
type PageInstance = Page.PageInstance &
	WechatMiniprogram.Page.InstanceMethods<any>

// #ifdef MP-WEIXIN

// 获取当前页面实例,数组最后一项
const instance = pages.at(-1) as PageInstance

// 页面渲染完毕，绑定动画效果
onReady(() => {
	// 动画效果,导航栏背景色
	instance.animate(
		'.navbar', // 选择器 多个空格隔开
		[{ backgroundColor: 'transparent' }, { backgroundColor: '#f8f8f8' }], // 动画
		2000, // 动画持续时长
		{
			scrollSource: '#scroller', // 以谁滚动触发动画
			timeRange: 2000, // 时间长度
			startScrollOffset: 0, // 开始滚动偏移量
			endScrollOffset: 50, // 停止滚动偏移量
		}
	)
	// 动画效果,导航栏标题
	instance.animate(
		'.title', // .navbar .title
		[{ color: 'transparent' }, { color: '#000' }],
		2000,
		{
			scrollSource: '#scroller',
			timeRange: 2000,
			startScrollOffset: 0,
			endScrollOffset: 50,
		}
	)
	// 动画效果,导航栏返回按钮
	instance.animate('.back', [{ color: '#fff' }, { color: '#000' }], 2000, {
		scrollSource: '#scroller',
		timeRange: 2000,
		startScrollOffset: 0,
		endScrollOffset: 50,
	})
})

// #endif

/**
 * 获取物流信息 -- 获取订单详情时 --状态 >= 待收货 时 调用
 * 模拟发货后应该再次调用此接口 -- 正式环境商家发货
 */
const logisticList = ref<LogisticItem[]>([])
const getLogisticList = async () => {
	const res = await getOrderLogisticsApi(id)
	logisticList.value = res.list
}

// 获取订单详情
const orderDetail = ref<OrderDetail>()
const getOrderDetail = async () => {
	const result = await getOrderDetailApi(id)
	orderDetail.value = result
	// 获取物流信息 -- 状态 >= 待收货 时 调用
	if (orderDetail.value.orderState < OrderState.WaitForReceived) return
	getLogisticList()
}

onLoad(() => getOrderDetail())

// 倒计时结束 修改订单状态为已取消
const onTimeUp = () => (orderDetail.value!.orderState = OrderState.Cancelled)

// 订单支付
const onOrderPay = async () => {
	// 开发环境 DEV
	if (import.meta.env.DEV) {
		// 开发环境 -- 模拟支付
		await getPayMockApi({ orderId: id })
	} else {
		// 正式环境支付 -- 1.获取支付订单信息，
		const res = await getWxPayApi({ orderId: id })

		// uni.requestPayment(res) -- res:UniApp.RequestPaymentOptions
		// 2.调用微信支付API -- 弹框输密码
		await wx.requestPayment(res)
	}
	// 修改订单状态
	orderDetail.value!.orderState = OrderState.WaitForDelivery
	// 关闭当前页，再跳转支付结果页
	uni.redirectTo({ url: `/pagesOrder/payment/payment?id=${id}` })
}

// 模拟发货 -- 更改 订单状态
const onOrderDelivery = async () => {
	// 仅在开发环境使用,生产环境会剔除以下代码(tree shaking)
	if (import.meta.env.DEV) {
		await getOrderConsignmentApi(id)
		uni.showToast({ icon: 'success', title: '模拟发货完成' })
		orderDetail.value!.orderState = OrderState.WaitForReceived
		// 再次获取物流信息
		getLogisticList()
	}
}

// 确认收货
const onOrderConfirm = () => {
	// 二次确认弹窗
	uni.showModal({
		content: '为保障您的权益，请收到货并确认无误后，再确认收货',
		confirmColor: '#27BA9B',
		success: async success => {
			if (success.confirm) {
				const res = await putOrderConfirmApi(id)
				// 更新订单状态
				orderDetail.value = res
			}
		},
	})
}

// 删除订单
const onDeleteOrder = () => {
	// 二次确认
	uni.showModal({
		content: '是否删除订单',
		confirmColor: '#27BA9B',
		success: async success => {
			if (success.confirm) {
				await deleteOrderApi({ ids: [id] })
				uni.redirectTo({ url: '/pagesOrder/list/list' })
			}
		},
	})
}

// 取消订单
const onOrderCancel = async () => {
	// 发送请求
	const res = await putOrderCancelApi(id, { cancelReason: reason.value })
	// 更新订单信息
	orderDetail.value = res
	// 关闭弹窗
	popup.value?.close?.()
	// 轻提示
	uni.showToast({ icon: 'none', title: '订单取消成功' })
}
</script>
<style lang="scss">
/* #ifdef H5 */

// css animation-timeline
@keyframes bg-color-grow {
	from {
		background-color: transparent;
	}
	to {
		background-color: #f8f8f8;
	}
}
@keyframes title-color-grow {
	from {
		color: transparent;
	}
	to {
		color: #000;
	}
}
@keyframes back-color-grow {
	from {
		color: #fff;
	}
	to {
		color: #000;
	}
}
#scroller {
	scroll-timeline-name: --scroll-container;
	scroll-timeline-axis: block; // 默认 block
	// 可简写为
	// scroll-timeline: --scroll-container;
}

/* #endif */

.symbol::before {
	content: '¥';
	font-size: 80%;
	margin-right: 2rpx;
}
.navbar {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 9;
	width: 750rpx;
	background-color: transparent;
	/* #ifdef H5 */
	animation: bg-color-grow 2s linear;
	animation-timeline: --scroll-container;
	animation-range: 0 100rpx;
	/* #endif */
	.back {
		position: absolute;
		left: 0;
		height: 88rpx;
		width: 88rpx;
		line-height: 88rpx;
		font-size: 44rpx;
		text-align: center;
		color: #fff;
		/* #ifdef H5 */
		animation: back-color-grow 2s linear;
		animation-timeline: --scroll-container;
		animation-range: 0 100rpx;
		/* #endif */
	}
	.title {
		height: 88rpx;
		line-height: 88rpx;
		font-size: 32rpx;
		text-align: center;
		color: transparent;
		/* #ifdef H5 */
		animation: title-color-grow 2s linear;
		animation-timeline: --scroll-container;
		animation-range: 0 100rpx;
		/* #endif */
	}
}
.overview {
	line-height: 1;
	padding-bottom: 30rpx;
	text-align: center;
	color: #fff;
	background: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/order_bg.png)
		no-repeat center/cover;
	.status {
		font-size: 36rpx;
	}
	.status::before {
		margin-right: 6rpx;
		font-weight: 500;
	}
	.tips {
		display: flex;
		justify-content: center;
		align-items: baseline;
		margin: 30rpx 0;
		font-size: 28rpx;
		.money {
			margin-right: 30rpx;
		}
		.time {
			margin-right: 6rpx;
		}
	}
	.button {
		width: 260rpx;
		height: 64rpx;
		margin: 0 auto;
		line-height: 64rpx;
		font-size: 28rpx;
		color: $primary-color;
		border-radius: 68rpx;
		background-color: #fff;
	}
	.button-group {
		margin-top: 30rpx;
	}
}
.shipment {
	line-height: 1.4;
	margin: 20rpx 20rpx 0;
	padding: 0 20rpx;
	border-radius: 10rpx;
	background-color: #fff;
	.item {
		background-image: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/car.png);
		border-bottom: 1rpx solid #eee;
	}
	.locate {
		background-image: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/locate.png);
	}
	.item,
	.locate {
		min-height: 120rpx;
		padding: 30rpx 30rpx 25rpx 75rpx;
		background-size: 50rpx;
		background-repeat: no-repeat;
		background-position: 6rpx center;
	}
	.text-one {
		font-size: 26rpx;
		color: #444;
		&.item {
			line-height: 65rpx;
		}
	}
	.text-two {
		font-size: 24rpx;
		color: #666;
	}
}

.goods {
	margin: 20rpx 20rpx 0;
	padding: 30rpx 20rpx 0;
	border-radius: 10rpx;
	background-color: #fff;
	overflow: hidden;
	.navigator {
		display: flex;
		margin: 20rpx 0;
	}

	.cover {
		width: 170rpx;
		height: 170rpx;
		border-radius: 10rpx;
		margin-right: 20rpx;
	}

	.meta {
		flex: 1;
	}

	.name {
		height: 80rpx;
		font-size: 26rpx;
		color: #444;
	}

	.attrs {
		line-height: 1.8;
		padding: 0 15rpx;
		margin-top: 6rpx;
		font-size: 24rpx;
		border-radius: 4rpx;
		color: #888;
		background-color: #f7f7f8;
	}

	.prices {
		display: flex;
		align-items: baseline;
		margin-top: 6rpx;
		font-size: 24rpx;
		.price {
			flex: 1;
			font-size: 24rpx;
			color: #999;
		}
		.count {
			font-size: 26rpx;
			color: #444;
		}
	}

	.action {
		display: flex;
		justify-content: flex-end;
		padding: 30rpx 0;
		border-bottom: 1rpx solid #eee;

		.button {
			width: 200rpx;
			height: 60rpx;
			text-align: center;
			justify-content: center;
			line-height: 60rpx;
			margin-left: 20rpx;
			border-radius: 60rpx;
			border: 1rpx solid #ccc;
			font-size: 26rpx;
			color: #444;
		}

		.primary {
			color: $primary-color;
			border-color: $primary-color;
		}
	}

	.row {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 10rpx 0;
		line-height: 1;
		font-size: 26rpx;
		color: #666;
		&.row-top {
			margin-top: 20rpx;
		}
		&.row-bottom {
			margin-bottom: 20rpx;
		}
		.primary {
			color: #cf4444;
			font-size: 36rpx;
		}
	}
}
.detail {
	line-height: 1;
	padding: 30rpx 20rpx 20rpx;
	margin: 20rpx 20rpx 0;
	font-size: 26rpx;
	color: #666;
	border-radius: 10rpx;
	background-color: #fff;

	.title {
		font-size: 30rpx;
		color: #444;
		margin-bottom: 20rpx;
	}
	.row {
		display: inline-block;
	}
	.item {
		padding: 10rpx 0;
	}
	.copy {
		border-radius: 20rpx;
		font-size: 20rpx;
		border: 1px solid #ccc;
		padding: 5rpx 10rpx;
		margin-left: 10rpx;
	}
}

// .toolbar-height {
// 	height: 100rpx;
// 	box-sizing: content-box;
// }

.toolbar {
	display: flex;
	justify-content: flex-end;

	position: fixed;
	left: 0;
	right: 0;
	bottom: calc(var(--window-bottom));
	z-index: 1;

	padding: 20rpx;
	border-top: 1rpx solid #ededed;
	background-color: #fff;

	.button {
		width: 200rpx;
		height: 72rpx;
		line-height: 72rpx;
		text-align: center;
		margin-left: 15rpx;
		font-size: 26rpx;
		border-radius: 72rpx;
		border: 1rpx solid #ccc;
		color: #444;
		&.primary {
			color: #fff;
			background-color: $primary-color;
		}
		&.secondary {
			color: $primary-color;
			border-color: $primary-color;
		}
	}
}

.popup-root {
	padding: 30rpx 30rpx 0;
	border-radius: 10rpx 10rpx 0 0;
	overflow: hidden;
	font-size: 28rpx;
	.title {
		font-size: 30rpx;
		text-align: center;
		margin-bottom: 30rpx;
	}
	.tips {
		padding: 0 20rpx;
		color: #444;
		margin-bottom: 12rpx;
	}

	.cell {
		display: flex;
		justify-content: space-between;
		padding: 15rpx 20rpx;
		color: #666;
	}

	.icon::before {
		font-size: 38rpx;
		color: #999;
	}

	.icon-checked::before {
		color: $primary-color;
	}
	.footer {
		display: flex;
		justify-content: center;
		padding: 30rpx 0;
		font-size: 28rpx;
		color: #444;
		.button {
			width: 320rpx;
			margin: 0 20rpx;
			color: #444;
			border-radius: 50rpx;
			border: 1rpx solid #ccc;
		}
		.primary {
			color: #fff;
			background-color: $primary-color;
			border: none;
		}
	}
}
</style>
